#include "StdAfx.h"
#include "ESMTPClient.h"

#define WIN32_LEAN_AND_MEAN
#define _HAS_EXCEPTIONS 1
#include <windows.h>

#include <stdlib.h>
#include <stdio.h>
#include "conio.h"

#include <cctype>

#include <typeinfo>
using namespace std;

// Need to link with Ws2_32.lib, Mswsock.lib, and Advapi32.lib
#pragma comment (lib, "Ws2_32.lib")
#pragma comment (lib, "Mswsock.lib")
#pragma comment (lib, "AdvApi32.lib")

#define DEFAULT_BUFLEN 512
#define DEFAULT_PORT "25"

#include "tool.h"


namespace libdmail
{
	using namespace tool;

	ESMTPClient::ESMTPClient(void)
	{
	}

	ESMTPClient::~ESMTPClient(void)
	{
	}

	int ESMTPClient::connectServer(string mailServer, int port)
	{
		WSADATA wsaData;
	
		struct addrinfo *result = NULL,
						*ptr = NULL,
						hints;
	
		int iResult;
	
		// Initialize Winsock
		iResult = WSAStartup(MAKEWORD(2,2), &wsaData);
		if (iResult != 0) {
			printf("WSAStartup failed with error: %d\n", iResult);
			return 1;
		}

		ZeroMemory( &hints, sizeof(hints) );
		hints.ai_family = AF_UNSPEC;
		hints.ai_socktype = SOCK_STREAM;
		hints.ai_protocol = IPPROTO_TCP;

		// Resolve the server address and port
		iResult = getaddrinfo(mailServer.c_str(), DEFAULT_PORT, &hints, &result);
		if ( iResult != 0 ) {
			printf("getaddrinfo failed with error: %d\n", iResult);
			WSACleanup();
			return 1;
		}
		
		// Attempt to connect to an address until one succeeds
		for(ptr=result; ptr != NULL ;ptr=ptr->ai_next) {

			// Create a SOCKET for connecting to server
			ConnectSocket = socket(ptr->ai_family, ptr->ai_socktype, 
				ptr->ai_protocol);
			if (ConnectSocket == INVALID_SOCKET) {
				printf("socket failed with error: %ld\n", WSAGetLastError());
				WSACleanup();
				return 1;
			}
	 
			// Connect to server.
			iResult = connect( ConnectSocket, ptr->ai_addr, (int)ptr->ai_addrlen);
			if (iResult == SOCKET_ERROR) {
				closesocket(ConnectSocket);
				ConnectSocket = INVALID_SOCKET;
				continue;
			}
			break;
		}

		unsigned long iNonBlock = 1;
		iResult = ioctlsocket(ConnectSocket, FIONBIO, &iNonBlock);

		if (iResult != NO_ERROR)
		{
			printf("ioctlsocket failed with error: %ld\n", iResult);
		}

		//freeaddrinfo(result);

		if (ConnectSocket == INVALID_SOCKET) {
			printf("Unable to connect to server!\n");
			WSACleanup();
			return 1;
		}

		return 0;

	}

	int ESMTPClient::disconnectServer()
	{
		int iResult;
		// shutdown the connection since no more data will be sent
		iResult = shutdown(ConnectSocket, SD_SEND);
		if (iResult == SOCKET_ERROR) {
			printf("shutdown failed with error: %d\n", WSAGetLastError());
			closesocket(ConnectSocket);
			WSACleanup();
			return 1;
		}
	 
		// cleanup
		closesocket(ConnectSocket);
		WSACleanup();

		return 0;
	}

	int ESMTPClient::sendMail(string mailServer, int port, Mail *mail)
	{
		int iConnect = this->connectServer(mailServer.c_str(), port);

		if (0 != iConnect)
		{
			return iConnect;
		}

		mEsmpt.setMail(mail);

		int iResult;
		fd_set readfds;
		fd_set writefds;
		struct timeval tv;

		tv.tv_sec = 0;
		tv.tv_usec = 0;
		    
		char recvbuf[DEFAULT_BUFLEN];
		int recvbuflen = DEFAULT_BUFLEN;
	    
		char recvCache[DEFAULT_BUFLEN];
		memset(recvCache, 0, DEFAULT_BUFLEN);
 
		do {
			FD_ZERO(&readfds);
			FD_ZERO(&writefds);
			FD_SET(ConnectSocket, &readfds);
			FD_SET(ConnectSocket, &writefds);
	 
			// don't care about writefds and exceptfds:
			int i = select(ConnectSocket+1, &readfds, NULL, NULL, &tv);

			if (0 < i)
			{
				if (FD_ISSET(ConnectSocket, &readfds))
				{
					iResult = recv(ConnectSocket, recvbuf, recvbuflen, 0);

					if ( iResult > 0 ) 
					{
						recvbuf[iResult] = '\0';

						strcat(recvCache,recvbuf);

						printf("-----%s-----", recvCache);
						
						if(mEsmpt.response(recvCache))
						{
							printf("S:%s", recvCache);

							memset(recvCache, 0, DEFAULT_BUFLEN);
						}
					}
					else if ( iResult == 0 ) {
						printf("Connection closed\n");
						break;
					}
					else {
						printf("recv failed with error: %d\n", WSAGetLastError());
						break;
					}
				}
			}

			// don't care about readfds and exceptfds:
			i = select(ConnectSocket+1, NULL, &writefds, NULL, &tv);

			if (0 < i)
			{
				if (FD_ISSET(ConnectSocket, &writefds))
				{
					string command = mEsmpt.request();

					if ("NONE" != command) 
					{
						// Send an initial buffer
						iResult = send( ConnectSocket, command.c_str(), (int)command.length(), 0 );
						
						printf("C:%s", command.c_str());

						if (iResult == SOCKET_ERROR) {
							printf("send failed with error: %d\n", WSAGetLastError());
							closesocket(ConnectSocket);
							WSACleanup();
							return 1;
						}									 
					}
				}
			}

			if (SOCKET_ERROR == i)
				printf("Socket failed with error in select: %d\n", WSAGetLastError());
		 
		} while(1);
		 

		// shutdown the connection since no more data will be sent
		iResult = shutdown(ConnectSocket, SD_SEND);
		if (iResult == SOCKET_ERROR) {
			printf("shutdown failed with error: %d\n", WSAGetLastError());
			closesocket(ConnectSocket);
			WSACleanup();
			return 1;
		}
	 
		// cleanup
		closesocket(ConnectSocket);
		WSACleanup();

	}
}